package com.xbongbong.paas.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.aliyun.oss.common.comm.ResponseMessage;
import com.aliyun.oss.model.OSSObject;
import com.xbongbong.paas.constant.ExcelConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.ImportRedisHelper;
import com.xbongbong.paas.help.ImportSendHelper;
import com.xbongbong.paas.help.OssHelper;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.ImportStatusPojo;
import com.xbongbong.paas.pojo.dto.ExcelTemplateDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.vo.ImportFormDataVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisKeyPojo;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.HandleImportService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.util.URLEncodeUtils;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.pojo.dto.PaasConfigGetDTO;
import com.xbongbong.pro.pojo.vo.PaasConfigGetVO;
import com.xbongbong.pro.service.toolbox.subform.PaasConfigService;
import com.xbongbong.pro.webimport.LinkFormImportPojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.export.ImportConstant;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.product.PriceSetEnum;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.service.toolbox.help.PackageStatusHelp;
import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 *
 * @author 魏荣杰
 * @date 2019/11/11 2:48 下午
 * @since v4.6.0
 * @version v4.6.0
 */
@Component
public class ExcelReaderHelper {

    private static final Logger LOG = LoggerFactory.getLogger(ExcelReaderHelper.class);

    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private HandleImportService handleImportService;
    @Resource
    private ImportHelper importHelper;
    @Resource
    private ImportSendHelper importSendHelper;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private PackageStatusHelp packageStatusHelp;
    @Resource
    private ImportRedisHelper importRedisHelper;
    @Resource
    private PaasConfigService paasConfigService;
    @Resource
    private OssHelper ossHelper;

    /**
     * Description: 导入
     * @param importFormDataDTO
     * @return com.xbongbong.paas.pojo.vo.ImportFormDataVO
     * @author 魏荣杰
     * @date 2019/11/21 3:17 下午
     * @since v4.6.0
     */
    @Async(value = "importThreadPool")
    public ImportFormDataVO importExcel(ImportFormDataDTO importFormDataDTO) throws XbbException {

        ImportFormDataVO importFormDataVO = new ImportFormDataVO();

        String corpid = importFormDataDTO.getCorpid();
        String userId = importFormDataDTO.getUserId();

        // 用户缓存处理
        String hashKey = corpid + "_" + userId;
//        ImportStatusPojo statusPojo = JsonHelperUtil.parseObject(paasRedisHelper.getValue(RedisPrefixConstant.IMPORT_STATUS_KEY,hashKey),ImportStatusPojo.class);
//        String value = paasRedisHelper.getValue(RedisPrefixConstant.IMPORT_START_FLAG_KEY, hashKey);
//        if (statusPojo != null && !statusPojo.getFinish() && Objects.equals(value, BasicConstant.ONE_STRING)) {
////            // 上次导入任务未结束
//            formatThrowExceptionToRedis(hashKey, ImportErrorCodeEnum.API_ERROR_235001.getCode(), ImportErrorCodeEnum.API_ERROR_235001.getMsg());
//            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235001);
//        }

        paasRedisHelper.setValue(RedisPrefixConstant.IMPORT_START_FLAG_KEY, hashKey, BasicConstant.ONE_STRING, TimeConstant.SECONDS_EIGHT_HOUR);

        // 上次导入状态缓存清除
        String formHashKey = hashKey + "_" + importFormDataDTO.getFormId();
        List<RedisKeyPojo> keyPojos = new ArrayList<>();
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_STATUS_KEY, hashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_ERROR_EXCEL_KEY, formHashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_UPDATE_EXCEL_KEY, formHashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_REPEAT_DATA_LIST_KEY, formHashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_NO_SIGN_EXCEL_KEY, formHashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_LOG_TIME, hashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_LOG_START_TIME, hashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_ERROR_EXCEL_OSS_KEY, hashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_UPDATE_EXCEL_OSS_KEY, hashKey));
        keyPojos.add(new RedisKeyPojo(RedisPrefixConstant.IMPORT_NO_SIGN_EXCEL_KEY, hashKey));

        paasRedisHelper.removeValue(keyPojos);

        InputStream fileInputStream;
        try {
            String url = importFormDataDTO.getFileUrl();
            String decodeUrl = URLEncodeUtils.decodeURL(url);
            int indexOf = decodeUrl.indexOf(ProBaseConfig.getProjectName());
            String key = decodeUrl.substring(indexOf);

            if (StringUtil.isNotEmpty(key) && key.endsWith(ExcelConstant.EXCEL03_EXTENSION)) {
                throw new XbbException(ImportErrorCodeEnum.API_ERROR_235026);
            }

            OSSObject ossObject = ossHelper.getObjectInputStream(key);
            fileInputStream = ossObject.getObjectContent();
            if (Objects.nonNull(fileInputStream)) {
                ResponseMessage response = ossObject.getResponse();
                Map<String, String> headers = response.getHeaders();
                String lengthStr = headers.get(HttpHeaders.CONTENT_LENGTH);
                if (StringUtil.isNotEmpty(lengthStr)) {
                    Long length = Long.valueOf(lengthStr);
                    if (length <= 0L) {
                        throw new XbbException(ImportErrorCodeEnum.API_ERROR_235071);
                    }
                }
            }


//            MultipartFile file = importFormDataDTO.getFile();
//            String name = file.getOriginalFilename();
//            if (StringUtil.isNotEmpty(name) && name.endsWith(ExcelConstant.EXCEL03_EXTENSION)) {
//                throw new XbbException(ImportErrorCodeEnum.API_ERROR_235026);
//            }
//            fileInputStream = file.getInputStream();
        } catch (XbbException e) {
            formatThrowExceptionToRedis(hashKey, e.getCode(), e.getMsg());
            throw e;
        } catch (Exception e) {
            formatThrowExceptionToRedis(hashKey, ImportErrorCodeEnum.API_ERROR_235002.getCode(), ImportErrorCodeEnum.API_ERROR_235002.getMsg());

            LOG.error("导入excel文件错误",e);
            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235002);
        }
        try {
            List<FieldAttrEntityForImport> fieldAttrList = getFieldAttrEntityForImports(importFormDataDTO, corpid);
            // 检测是否含有子表单，方便确定从第几行开始读取数据。
            int startRowIndex = ImportConstant.VALUE_STAR_ROW_INDEX;
            startRowIndex += importHelper.hasSubForm(fieldAttrList) - 1;

            importFormDataDTO.setFile(null);
            // 获取子表单和关联产品行数的限制
            PaasConfigGetDTO paasConfigGetDTO = new PaasConfigGetDTO(corpid);
            PaasConfigGetVO paasConfigGetVO = paasConfigService.getSubFormConfig(paasConfigGetDTO);
            ExcelReaderUtil.readXlsxExcel(fileInputStream, new ExcelImportReadDataDelegated(importSendHelper, paasRedisHelper, handleImportService, importRedisHelper, paasConfigGetVO), startRowIndex, fieldAttrList, importFormDataDTO, importSendHelper, handleImportService, paasRedisHelper, importRedisHelper, packageStatusHelp);

        } catch (XbbException e) {
            paasRedisHelper.removeValue(keyPojos);

            formatThrowExceptionToRedis(hashKey, e.getCode(), e.getMsg());

            throw e;
        } catch (NotOfficeXmlFileException e) {
            paasRedisHelper.removeValue(keyPojos);

            formatThrowExceptionToRedis(hashKey, ImportErrorCodeEnum.API_ERROR_235029.getCode(), ImportErrorCodeEnum.API_ERROR_235029.getMsg());

            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235029);
        } catch (IOException e) {
            paasRedisHelper.removeValue(keyPojos);

            formatThrowExceptionToRedis(hashKey, ImportErrorCodeEnum.API_ERROR_235067.getCode(), ImportErrorCodeEnum.API_ERROR_235067.getMsg());

            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235067);
        } catch (Exception e) {
            LOG.error("com.xbongbong.paas.util.ExcelReaderHelper.importExcel error", e);

            formatThrowExceptionToRedis(hashKey, SystemErrorCodeEnum.API_ERROR_100001.getCode(), SystemErrorCodeEnum.API_ERROR_100001.getMsg());

            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        } finally {
            if (Objects.nonNull(fileInputStream)) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    LOG.error("com.xbongbong.paas.util.ExcelReaderHelper.importExcel fileInputStream close fail", e);
                }
            }
        }

        return importFormDataVO;
    }

    private void formatThrowExceptionToRedis(String hashKey, Integer code, String msg) {
        ImportStatusPojo statusPojo = new ImportStatusPojo();
        statusPojo.setCode(code);
        statusPojo.setMsg(msg);
        paasRedisHelper.setValue(RedisPrefixConstant.IMPORT_STATUS_KEY, hashKey, JSON.toJSONString(statusPojo), TimeConstant.SECONDS_EIGHT_HOUR);
        //移除导入标记
        paasRedisHelper.removeValue(RedisPrefixConstant.IMPORT_START_FLAG_KEY, hashKey);
    }

    private List<FieldAttrEntityForImport> getFieldAttrEntityForImports(ImportFormDataDTO importFormDataDTO, String corpid) throws XbbException {
        Integer businessType = importFormDataDTO.getBusinessType();
        PaasFormExplainEntity paasFormExplainEntity;
        if (Objects.equals(importFormDataDTO.getBusinessType(), XbbRefTypeEnum.ORI_STOCK.getCode())) {
            paasFormExplainEntity = paasFormExplainModel.getSystemDefaultExplain(XbbRefTypeEnum.ORI_STOCK.getCode());
        } else if (Objects.equals(importFormDataDTO.getBusinessType(), XbbRefTypeEnum.PRICE_SET_PRODUCT.getCode())) {
            JSONArray fieldAttrList = importHelper.getFieldAttrList(corpid);
            JSONArray fieldList = new JSONArray();
            for (int i = 0; i < fieldAttrList.size(); i++) {
                JSONObject jsonObject = fieldAttrList.getJSONObject(i);
                if (Objects.equals(jsonObject.getString("attr"), PriceSetEnum.PRIORITY.getAttr())) {
                    continue;
                } else if (Objects.equals(jsonObject.getString("attr"), PriceSetEnum.NAME.getAttr())) {
                    jsonObject.put("noRepeat", 1);
                } else if (Objects.equals(jsonObject.getString("attr"), PriceSetEnum.START_TIME.getAttr())) {
                    jsonObject.put("fieldType", FieldTypeEnum.DATETIME.getType());
                } else if (Objects.equals(jsonObject.getString("attr"), PriceSetEnum.END_TIME.getAttr())) {
                    jsonObject.put("fieldType", FieldTypeEnum.DATETIME.getType());
                }
                fieldList.add(jsonObject);
            }
            paasFormExplainEntity = new PaasFormExplainEntity();
            paasFormExplainEntity.setExplains(fieldList.toJSONString());
        }else if (Objects.equals(importFormDataDTO.getBusinessType(), XbbRefTypeEnum.KNOWLEDGE_BASE.getCode())) {
            paasFormExplainEntity = paasFormExplainModel.getSystemDefaultExplain(XbbRefTypeEnum.KNOWLEDGE_BASE.getCode());
        } else {
            paasFormExplainEntity = paasFormExplainModel.getByFormId(importFormDataDTO.getFormId(), importFormDataDTO.getCorpid());
            if (paasFormExplainEntity == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
        }
        String explains = paasFormExplainEntity.getExplains();
        // 获取表单字段实体
        List<FieldAttrEntityForImport> fieldAttrList = JSON.parseArray(explains, FieldAttrEntityForImport.class);
        List<String> attrList = importFormDataDTO.getAttrList();
        if (CollectionsUtil.isNotEmpty(attrList)) {
            Map<String, FieldAttrEntity> explainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<FieldAttrEntity> fieldAttrs = JSON.parseArray(explains, FieldAttrEntity.class);
            for (FieldAttrEntity fieldAttrEntity : fieldAttrs) {
                String attr = fieldAttrEntity.getAttr();
                if (attrList.contains(attr)) {
                    explainMap.put(attr, fieldAttrEntity);
                }
            }
            importFormDataDTO.setExplainMap(explainMap);
            //过滤不需要导入的字段
            fieldAttrList.removeIf(item -> !attrList.contains(item.getAttr()));
        } else {
            importFormDataDTO.setExplainMap(ExplainUtil.getExplainMap(explains, null));
        }
        importFormDataDTO.setDistributorMark(paasFormExplainEntity.getDistributorMark());
        // 处理关联新建表单
        if (Objects.equals(importFormDataDTO.getSaasMark(), SaasMarkEnum.SAAS.getCode())) {
            LinkFormImportPojo linkFormImportPojo = new LinkFormImportPojo();
            BeanUtil.copyProperties(importFormDataDTO, linkFormImportPojo);
            linkFormImportPojo.setFieldAttrEntityForImportList(fieldAttrList);
            linkFormImportPojo.setFormImportOrExport(ImportConstant.FROM_IMPORT);
            handleImportService.handleLinkForm(linkFormImportPojo, paasFormExplainEntity.getDistributorMark());
        }
        // 过滤不需要导入的字段
        handleImportService.filterUnImportFields(fieldAttrList, importFormDataDTO.getSaasMark(), ImportConstant.FROM_IMPORT, importFormDataDTO.getBusinessType(), importFormDataDTO.getCorpid(), importFormDataDTO.getFormId(), importFormDataDTO.getIsFileImport());
        // 处理公有的需要转换的字段
        FormDataListDTO formDataListDTO = new FormDataListDTO(importFormDataDTO.getSaasMark(), importFormDataDTO.getBusinessType(), importFormDataDTO.getFormId());
        formDataListDTO.setCorpid(importFormDataDTO.getCorpid());
        handleImportService.handleCommonNeedTransferFields(fieldAttrList, formDataListDTO);
        JSONArray jsonArray = new JSONArray();
        if (Objects.equals(importFormDataDTO.getSaasMark(), SaasMarkEnum.SAAS.getCode())) {
            // SaaS字段解释特处理
            ExcelTemplateDTO excelTemplateDTO = new ExcelTemplateDTO();
            BeanUtil.copyProperties(importFormDataDTO, excelTemplateDTO);
            excelTemplateDTO.setFormImportOrExport(ImportConstant.FROM_IMPORT);
            handleImportService.changeFieldShowTypeForImport(excelTemplateDTO, fieldAttrList);
            jsonArray = handleImportService.handleSpecialExplain(fieldAttrList, excelTemplateDTO);
        } else {
            fieldAttrList.removeIf(fieldAttrEntity->Objects.equals("extensionField",fieldAttrEntity.getSaasAttr()));
            handleImportService.setTitleTag(fieldAttrList);
            jsonArray = JSON.parseArray(JSON.toJSONString(fieldAttrList, SerializerFeature.DisableCircularReferenceDetect));
        }
        /**处理字段解释 结束*/
        //为下面报价单分组添加的组号和版本号提前塞入fieldAttrList（getSaasExcelValue分组要用）
        if (Objects.equals(businessType, XbbRefTypeEnum.QUOTATION.getCode())) {
            fieldAttrList = JSON.parseArray(JSON.toJSONString(jsonArray, SerializerFeature.DisableCircularReferenceDetect), FieldAttrEntityForImport.class);
        }
        return fieldAttrList;
    }

}